#include "entity.h"

int UNIQUE_ENTITY_ID = 1;

CEntity::CEntity()
{

	m_UniqueID = UNIQUE_ENTITY_ID++;
	
	m_SizeOverride.SetXY( -1, -1 );
	m_ShadowScale.SetXY( .8, .1 );
	
	m_pEntityLogic = NULL;

	m_bOnScreen = false;
	
	m_bAnimating = false;
	m_CurSprite = -1;
	m_CurFrame = -1;
	m_TimeNextFrame = 0;	
	m_TimeLastFrame = 0;

	m_bEffectedByAirFriction = true;
	m_bEffectedByGravity = false;
	
	m_pCollisionBox = new CCollisionBox;
	
	m_Class = "Base";
	
	m_DrawLayer = 0;
	
	m_bXFlipped = false;
	m_bHasShadow = false;
	
	m_pShadowMat = NULL;
	
	m_CurSpriteBind = -1;
	
	m_ClassID = 0;
	
	m_Color.SetXYZ( 1.0, 1.0, 1.0 );
	m_Alpha = 1.0;
	
	m_bDeathFade = false;
	m_bDeathFadeOut = false;
	m_bPainFlashing = false;
	
	m_bSTSet = false;
	
	m_bDoEntLogic = true;
	
	
}

CEntity::~CEntity()
{

	m_pSprites.clear();
	m_SpriteBindings.clear();
	
	if( m_pCollisionBox )
		delete m_pCollisionBox;
	
	if( m_pEntityLogic )
		delete m_pEntityLogic;
	
}

void CEntity::AnimateThink()
{
	
	if( !m_bAnimating || m_CurSprite == -1 || m_pSprites[m_CurSprite]->GetFrameCount() <= 1 )
		return;

	if( m_TimeNextFrame < SDL_GetTicks() )
	{
		
		m_TimeLastFrame = SDL_GetTicks();
		
		if( ++m_CurFrame >= m_pSprites[m_CurSprite]->GetFrameCount() )
		{
		
			if( m_pSprites[m_CurSprite]->GetRepeatFrame() < 0 )
				m_CurFrame = 0;
			else
				m_CurFrame = m_pSprites[m_CurSprite]->GetRepeatFrame();
			
		}
		
		m_TimeNextFrame = SDL_GetTicks() + m_pSprites[m_CurSprite]->GetFramePause( m_CurFrame );
	
		
	}
	
}

void CEntity::ApplyAirFriction()
{
	
	if( !m_bEffectedByAirFriction )
		return;
	
	if( m_PhysVel.x < 0 )
	{
	
		m_PhysVel.x += AIR_FRICTION_CONSTANT * m_pEntityInterface->GetDPS();
		
		if( m_PhysVel.x > 0 )
			m_PhysVel.x = 0.0;
		
	} else if( m_PhysVel.x > 0 )
	{
	
		m_PhysVel.x -= AIR_FRICTION_CONSTANT * m_pEntityInterface->GetDPS();
		
		if( m_PhysVel.x < 0 )
			m_PhysVel.x = 0.0;		
		
	}
	
	if( m_PhysVel.y < 0 )
	{
	
		m_PhysVel.y += AIR_FRICTION_CONSTANT * m_pEntityInterface->GetDPS();
		
		if( m_PhysVel.y > 0 )
			m_PhysVel.y = 0.0;
		
	} else if( m_PhysVel.y > 0 )
	{
	
		m_PhysVel.y -= AIR_FRICTION_CONSTANT * m_pEntityInterface->GetDPS();
		
		if( m_PhysVel.y < 0 )
			m_PhysVel.y = 0.0;		
		
	}
	
}

void CEntity::ApplyPhysicsVelocity()
{

	m_Pos.x += m_PhysVel.x * m_pEntityInterface->GetDPS();
	m_Pos.y += m_PhysVel.y * m_pEntityInterface->GetDPS();
	
}

void CEntity::ApplyConstantVelocity()
{

	m_Pos.x += m_ConstVel.x * m_pEntityInterface->GetDPS();
	m_Pos.y += m_ConstVel.y * m_pEntityInterface->GetDPS();
	
}

void CEntity::ApplyGravity()
{
	
	if( !m_bEffectedByGravity )
		return;
	
	if( m_pEntityInterface->GetGameRules()->GetGameRule( "Gravity" ) == 0 )
		return;
	
	m_PhysVel.y += GRAVITY_CONSTANT * m_pEntityInterface->GetDPS();
		
	if( m_PhysVel.y > MAX_FALLING_SPEED_CONSTANT )
		m_PhysVel.y = MAX_FALLING_SPEED_CONSTANT;
	
}

void CEntity::BaseThink()
{
	
	AnimateThink();
	
	ApplyGravity();
	ApplyAirFriction();
	
	ApplyPhysicsVelocity();
	ApplyConstantVelocity();
	
	SyncCollisionBoxPos();

	if( m_pEntityLogic && m_bDoEntLogic )
		m_pEntityLogic->Think();
	
}

void CEntity::BaseDraw()
{
	
	int width = 1, height = 1;
	Vector2D offset;
	Vector2D v = m_Pos;
	
	bool textured = false;

	if( m_pSprites.size() == 0 )
		return;

	if( m_CurSprite >= 0 )
	{
		
		textured = true;
		
		width = m_pSprites[m_CurSprite]->GetFrameWidth( m_CurFrame );
		height = m_pSprites[m_CurSprite]->GetFrameHeight( m_CurFrame );
		offset = m_pSprites[m_CurSprite]->GetFrameOffset( m_CurFrame );

	} 
	
	if( m_SizeOverride.x > -1 )
	{
		
		width = m_SizeOverride.x;
		height = m_SizeOverride.y;
		
	}
	
	if( m_bHasShadow && m_pShadowMat )
	{
		
		PUSH_MATRIX;
		
			Draw::Translate( v.x + m_ShadowOffset.x, v.y + height + m_ShadowOffset.y, 0.0f );
			
			Draw::Scale( width * m_ShadowScale.x, height * m_ShadowScale.y, 1.0f );

			Draw::Color4f( 1.0f, 1.0f, 1.0f, .4f );
			
			m_pShadowMat->BindFrame( 0 );
			
			Draw::RawQuad();
			
			Draw::Color4f( 1.0f, 1.0f, 1.0f, 1.0f );
		
		 POP_MATRIX;
			
	}
	
	
	if( m_bXFlipped )
	{
		
		v.x += width;
		v.x -= offset.x;
		v.y += offset.y;
		
	} else
	{
		
		v.x += offset.x;
		v.y += offset.y;
	
	}
	
	if( textured )
	{
		
		glEnable( GL_TEXTURE_2D );
		m_pSprites[m_CurSprite]->BindFrame( m_CurFrame );
		
	} else
		glDisable( GL_TEXTURE_2D );
		
	PUSH_MATRIX;
	
		if( m_bSTSet )
			Draw::SetSTOffsets( m_ST1.x, m_ST1.y, m_ST2.x, m_ST2.y );
	
		Draw::Translate( v.x, v.y, v.z );
		
		if( m_bXFlipped )
			Draw::Scale( -1.0f, 1.0f, 1.0f );
		
		if( !m_bPainFlashing )
			Draw::Color4f( m_Color.x, m_Color.y, m_Color.z, m_Alpha );
		else if( m_bMidPainFlash )
		{
			
			glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
			//Draw::Color4f( 1.0, -1.0f, -1.0f, 1.0f );
			
		} 
		
		Draw::Scale( width, height, 1.0f );
	
		if( !m_bDeathFadeOut )
			Draw::RawQuad();
		
		if( m_bDeathFade )
		{
			
			glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
			Draw::Color4f( 1.0, 1.0f, 1.0f, 1.0f - m_Alpha );
			
			Draw::RawQuad();
			
			if( !m_bDeathFadeOut )
				m_Alpha -= 2.0f * m_pEntityInterface->GetDPS();
			else
				m_Alpha += 4.0f * m_pEntityInterface->GetDPS();
			
			if( m_Alpha < 0.0f ) 
			{
				m_Alpha = 0.0f;
				m_bDeathFadeOut = true;
			}
			
			if( m_Alpha > 1.0f ) 
				m_Alpha = 1.0f;
				
			glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
			
		}
		
		Draw::Scale( 1.0f, 1.0f, 1.0f );
		
		if( m_bPainFlashing )
		{
			
			if( m_bMidPainFlash )
				glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
		
			if( SDL_GetTicks() > m_NextMidPainFlash )
			{
				
				m_NextMidPainFlash = SDL_GetTicks() + PAIN_FLASH_SPEED;
				m_bMidPainFlash = !m_bMidPainFlash;
				
			}
			
			if( SDL_GetTicks() > m_DonePainFlashing )
			{
				
				m_bPainFlashing = false;
				
			}
			
		}
			
	POP_MATRIX;
		
	if( !textured )
		glEnable( GL_TEXTURE_2D );
	
}